﻿using Digitalmes.Application.Scada.Commands;
using Digitalmes.Domain;
using Digitalmes.Domain.Enums;
using ThingsEdge.Contracts;
using ThingsEdge.Contracts.Variables;

namespace Digitalmes.Infrastructure.Scada.Handlers;

/// <summary>
/// 工步过点数据处理。
/// </summary>
/// <remarks>
/// 此数据处理阶段在进站与出站之间。产品进站后，通过信号点监控和接收某部分过程数据，这与出站时过程数据一次打包发送不同。
/// </remarks>
/// <param name="logger"></param>
internal sealed class WorkstepHandler(ISender sender, ILogger<WorkstepHandler> logger) : IScadaHandler
{
    public async Task<ScadaResult> HandleAsync(RequestMessage message, CancellationToken cancellationToken = default)
    {
        var sn = message.GetString(TagDefinition.PLC_Workstep_SN);

        // 请求日志
        logger.LogInformation("[工步过点请求数据] {SN}, 工位：{WsCode}，数据：{Message}",
            sn ?? "",
            message.Schema.TagGroupName,
            message.Values.Select(s => new { s.TagName, s.Address, s.Value }).ToJson());

        if (string.IsNullOrWhiteSpace(sn))
        {
            return LoggerHelper.LogAndReturn(logger, "工步过点响应", message.Schema.TagGroupName!, ErrorCode.E1501);
        }

        int? passResult = message.GetData(TagDefinition.PLC_Archive_PassResult)?.GetInt();
        if (!passResult.HasValue || !Enum.IsDefined(typeof(PassEnum), passResult.Value))
        {
            return LoggerHelper.LogAndReturn(logger, "工步过点响应", message.Schema.TagGroupName!, ErrorCode.E1502);
        }

        int? index = message.GetData(TagDefinition.PLC_Workstep_Index)?.GetInt();

        WorkstepCommand command = new()
        {
            LineCode = message.Schema.ChannelName,
            WsCode = message.Schema.TagGroupName,
            SN = sn,
            PassResult = (PassEnum)passResult.Value,
            Index = index ?? 0,
            AttachData = message.Children(TagIdentity.Attach),
        };

        try
        {
            var result = await sender.Send(command, cancellationToken).ConfigureAwait(false);

            // 响应日志
            logger.LogInformation("[工步过点响应] {SN}, 工位：{WsCode}，状态: {State}, 消息: [{InnerErrorCode}]-{ErrMessage}; 回调值: {CallbackItems}",
                sn,
                message.Schema.TagGroupName,
                result.State.ToString(),
                result.InnerErrorCode.ToString(),
                result.GetErrorMessage(),
                result.CallbackItems.ToJson() ?? "[]");

            return result;
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "[工步过点服务处理异常] {SN}, 工位：{WsCode}",
                 sn,
                 message.Schema.TagGroupName);
            return ScadaResult.Error();
        }
    }
}
